﻿using System;
using System.Web.UI.WebControls;

namespace CommerceForUmbraco.usercontrols.usercontrols.commerce
{
    public partial class PWPagingControl : System.Web.UI.UserControl
    {
        #region Constants
        private const int MAX_PAGES = 5;
        #endregion

        #region Fields
        private bool suppressMessageFire = false;
        #endregion

        #region Event Plumbing

        public enum ProWorksPagingControlEventType
        {
            Normal,
            PageSizeOnly,
            CurrentPageOnly,
            SortOrderOnly
        }

        public class ProWorksPagingControlEventArgs : EventArgs
        {
            public int CurrentPageIndex = 0;
            public int PageSize = 0;
            public SortOrderClause SortOrderClause = null;
            public ProWorksPagingControlEventType EventType = ProWorksPagingControlEventType.Normal;

            public override string ToString()
            {
                return string.Format("Page Index: {0}, Page Size: {1}", CurrentPageIndex, PageSize);
            }
        }

        public class SortOrderClause
        {
            public string SortColumnName = "";
            public bool Ascending = true;

            override public string ToString()
            {
                return string.Format("{0}~{1}", this.SortColumnName, this.Ascending ? "ASC" : "DESC");
            }

            static public SortOrderClause FromString(string sortOrderDetails)
            {
                if (string.IsNullOrEmpty(sortOrderDetails))
                {
                    return null;
                }

                char[] delimiter = { '~' };
                string[] items = sortOrderDetails.Split(delimiter, StringSplitOptions.RemoveEmptyEntries);

                if (items == null || items.Length != 2)
                {
                    return null;
                }

                SortOrderClause clause = new SortOrderClause();
                clause.SortColumnName = items[0];
                clause.Ascending = items[1] == "DESC" ? false : true;

                return clause;
            }
        }
        
        public delegate void PagedControlChanged(object sender, ProWorksPagingControlEventArgs args);
        public event PagedControlChanged OnPagedControlChanged = null;

        private ProWorksPagingControlEventArgs GetCurrentStateEventArgs()
        {
            ProWorksPagingControlEventArgs args = new ProWorksPagingControlEventArgs();
         
            args.CurrentPageIndex = this.CurrentPageIndex;
            args.PageSize = Convert.ToInt32(this.ctrlPageSizeList.SelectedValue);
            args.SortOrderClause = SortOrderClause.FromString(this.ctrlSortOrderList.SelectedValue);

            // NOTE: the EventType is NOT set.  Defaults to Normal.
            // Caller should override for specific event types other than Normal, 
            // e.g., PageSizeOnly, SortColumnOnly, etc....

            return args;
        }
       
        #endregion

        #region Properties

        public bool IsBottomDisplay
        {
            get
            {
                if (ViewState["IsBottomDisplay"] == null)
                {
                    ViewState["IsBottomDisplay"] = false;
                }

                return Convert.ToBoolean(ViewState["IsBottomDisplay"]);
            }

            set 
            { 
                ViewState["IsBottomDisplay"] = value;

                // If this is a bottom display, hide the details
                this.ctrlNavDetailsPanel.Visible = !value;

                // Update the main div class depending on the context of the display
                this.ctrlRibbonWrapDiv.Attributes["class"] = value ? "bottomRibbonWrap" : "ribbonWrap";
            }
        }

        public int CurrentPageIndex
        {
            get
            {
                // Get value from hidden control...
                if (ViewState["CurrentPageIndex"] == null)
                {
                    return 0; // default page index of 0
                }
                else
                {
                    return Convert.ToInt32(ViewState["CurrentPageIndex"]);
                }
            }
            set
            {
                ViewState["CurrentPageIndex"] = (value >= 0 ? value : 0);
            }
        }

        public int TotalRows
        {
            get
            {
                if (ViewState["TotalRows"] == null)
                {
                    return 0; 
                }
                else
                {
                    return Convert.ToInt32(ViewState["TotalRows"]);
                }
            }
            set
            {
                ViewState["TotalRows"] = (value >= 0 ? value : 0);
            }
        }

        public int PageSize
        {
            get
            {
                if (ViewState["PageSize"] == null || 
                    Convert.ToInt32(ViewState["PageSize"]) <= 0)
                {
                    // NOTE: up to caller to seed with a default value
                    // A value of <= 0 is not allowed to prevent divide
                    // by zero.  This value may or may not make sense
                    // for the parent control UI.  Typically the default page
                    // size is 10 or 20, etc, so we default to something typical:
                    return 10; 
                }
                else
                {
                    return Convert.ToInt32(ViewState["PageSize"]);
                }
            }
            set
            {
                ViewState["PageSize"] = (value >= 0 ? value : 0);
            }
        }


        public string SortOrderDetails
        {
            get
            {
                return ViewState["SortOrderDetails"] as string;
            }
            set
            {
                ViewState["SortOrderDetails"] = value;
            }
        }
        #endregion

        #region Public Methods
        public void UpdatePageSizeInList(int pageSize)
        {
            // Typically called to sync the page selection
            // to that of another paging control...
            
            this.suppressMessageFire = true;

            this.ctrlPageSizeList.ClearSelection();

            foreach (ListItem li in this.ctrlPageSizeList.Items)
            {
                if (li.Value == pageSize.ToString())
                {
                    li.Selected = true;
                    break;
                }
            }

            this.PageSize = pageSize;

            this.suppressMessageFire = false;
        }

        public void UpdateSortOrderInList(string sortOrderDetails)
        {
            // Typically called to sync the page selection
            // to that of another paging control...

            this.suppressMessageFire = true;

            this.ctrlSortOrderList.ClearSelection();

            foreach (ListItem li in this.ctrlSortOrderList.Items)
            {
                if (li.Value == sortOrderDetails)
                {
                    li.Selected = true;
                    break;
                }
            }

            this.SortOrderDetails = sortOrderDetails;
            this.suppressMessageFire = false;
        }

        public void UpdateSortOrderList(SortOrderClause sortOrderClause)
        {
            // Typically called to sync the page selection
            // to that of another paging control...

            this.suppressMessageFire = true;

            this.ctrlSortOrderList.ClearSelection();

            foreach (ListItem li in this.ctrlSortOrderList.Items)
            {
                if (sortOrderClause != null && li.Value == sortOrderClause.ToString())
                {
                    li.Selected = true;
                    break;
                }
            }

            this.SortOrderDetails = sortOrderClause.ToString();

            this.suppressMessageFire = false;
        }

        public void InitSortOrderList(string[] sortDisplayNames, string[] sortOrderClauses, SortOrderClause selectedSortOrderClause)
        {
            this.ctrlSortOrderList.Items.Clear();

            // validate required items...
            if ( sortDisplayNames == null || sortOrderClauses == null ||
                 sortDisplayNames.Length == 0 || sortOrderClauses.Length == 0 ||
                 sortDisplayNames.Length != sortOrderClauses.Length ||
                 selectedSortOrderClause == null)
            {
                return;
            }

            bool hasSelected = false;
            for (int i = 0; i < sortDisplayNames.Length; i++)
            {
                ListItem li = new ListItem();
                li.Text = sortDisplayNames[i];
                li.Value = sortOrderClauses[i];

                if (selectedSortOrderClause.ToString() == sortOrderClauses[i] && 
                    hasSelected == false)
                {
                    li.Selected = true;
                    hasSelected = true;

                    // Cache this...
                    this.SortOrderDetails = selectedSortOrderClause.ToString();
                }

                this.ctrlSortOrderList.Items.Add(li);
            }
        }

        public void InitPageSizeList(int[] pageRanges, int selectedRange, int totalRows, bool appendAllItem)
        {
            this.ctrlPageSizeList.Items.Clear();

            // Need for postback re-create of controls...
            this.TotalRows = totalRows;

            if (pageRanges == null)
            {
                return;
            }

            bool hasSelection = false;
            foreach (int pageRange in pageRanges)
            {
                ListItem li = new ListItem();
                li.Text = pageRange.ToString();
                li.Value = pageRange.ToString();

                // One selection only...
                if (selectedRange == pageRange && hasSelection == false)
                {
                    li.Selected = true;
                    hasSelection = true;
                }

                this.ctrlPageSizeList.Items.Add(li);
            }

            if (appendAllItem)
            {
                ListItem li = new ListItem();
                li.Text = "All";
                li.Value = totalRows.ToString();

                this.ctrlPageSizeList.Items.Add(li);
            }
        }

        public void CreatePagingControl(int pageSize, int totalRows, int currentPageIndex)
        {
            if (totalRows <= 0)
            {
                this.ctrlPageDisplayingDetailsLabel.Text = "0 items.";
                return;
            }

            try
            {
                this.CurrentPageIndex = currentPageIndex;
                this.PageSize = pageSize;

                // WARNING: if not set correctly we can get into a recursive loop!
                bool sendCurrentPageAdjustmentMsg = false;
                bool forceRefreshAll = false;

                int iTotalPages = 1;
                if (totalRows >= this.PageSize)
                {
                    iTotalPages = totalRows / this.PageSize;

                    if ((totalRows % this.PageSize) > 0)
                    {
                        iTotalPages++;
                    }
                }
                else
                {
                    this.CurrentPageIndex = 0;
                    sendCurrentPageAdjustmentMsg = true;
                }
                
                if (this.CurrentPageIndex + 1 > iTotalPages)
                {
                    this.CurrentPageIndex = iTotalPages-2;
                    forceRefreshAll = true;
                }

                // Create the displayed page index numbers...
                this.ctrlPageIndexPlaceholder.Controls.Clear();

                // Create the "Previous" link...
                LinkButton pagePreviousIndexLinkCtrl = new LinkButton();
                pagePreviousIndexLinkCtrl.ID = "pagePreviousIndexLinkCtrl";
                pagePreviousIndexLinkCtrl.ToolTip = "Previous";
                pagePreviousIndexLinkCtrl.Click += new EventHandler(OnPageShowPrevious_Click);
                pagePreviousIndexLinkCtrl.Attributes.Add("class", "prev");
                pagePreviousIndexLinkCtrl.Enabled = (this.CurrentPageIndex > 0);
                this.ctrlPageIndexPlaceholder.Controls.Add(pagePreviousIndexLinkCtrl);

                int loopStart = 0;
                int loopMax = Math.Min(MAX_PAGES, iTotalPages);
                if (iTotalPages > 5 && this.CurrentPageIndex > 1)
                {
                    int testMax = this.CurrentPageIndex + 2;    // Try to get the current page in the center
                    if (testMax + 1 <= iTotalPages)
                    {
                        loopStart = this.CurrentPageIndex - 2;
                        loopMax = testMax + 1;
                    }
                    else
                    {
                        loopStart = iTotalPages - 5;
                        loopMax = iTotalPages;
                    }

                }

                for (int i = loopStart; i < loopMax /*Math.Min(MAX_PAGES, iTotalPages)*/; i++)
                {
                    LinkButton pageIndexLinkCtrl = new LinkButton();
                    pageIndexLinkCtrl.ID = "pageIndexLinkCtrl" + (i+1).ToString();
                    pageIndexLinkCtrl.Text = (i+1).ToString();
                    pageIndexLinkCtrl.Click += new EventHandler(OnPageIndexLink_Click);

                    if (i == this.CurrentPageIndex)
                    {
                        if (this.IsBottomDisplay)
                        {
                            pageIndexLinkCtrl.Attributes.Add("class", "pageNum bottom active");
                        }
                        else
                        {
                            pageIndexLinkCtrl.Attributes.Add("class", "pageNum active");
                        }
                    }
                    else
                    {
                        if (this.IsBottomDisplay)
                        {
                            pageIndexLinkCtrl.Attributes.Add("class", "pageNum bottom");
                        }
                        else
                        {
                            pageIndexLinkCtrl.Attributes.Add("class", "pageNum");
                        }
                    }

                    this.ctrlPageIndexPlaceholder.Controls.Add(pageIndexLinkCtrl);
                }
               
                //if (iTotalPages > MAX_PAGES)
                //{
                //    // NOTE: show a list of additional pages in a list - this will prevent page wrap
                //    // if/when there are many page results, (over 7 usually causes wrapping)
                //    // and we don't really want to implment the "..." logic...
                //    DropDownList additionalPagesDDList = new DropDownList();
                //    additionalPagesDDList.ID = "additionalPagesDDList";
                //    additionalPagesDDList.AutoPostBack = true;
                //    additionalPagesDDList.ToolTip = "Jump to Additional Pages";
                //    additionalPagesDDList.Attributes.Add("class", "dropstyle");
                //    additionalPagesDDList.SelectedIndexChanged += new EventHandler(OnExtendedPageDDListSelectChange);

                //    for (int i = MAX_PAGES + 1; i <= iTotalPages; i++)
                //    {
                //        ListItem li = new ListItem();
                //        li.Text = i.ToString();
                //        li.Value = i.ToString();

                //        if (this.CurrentPageIndex == (i - 1))
                //        {
                //            li.Selected = true;
                //        }

                //        additionalPagesDDList.Items.Add(li);
                //    }

                //    this.ctrlPageIndexPlaceholder.Controls.Add(additionalPagesDDList);
                //}

                // Create the "Next" link...
                LinkButton pageNextIndexLinkCtrl = new LinkButton();
                pageNextIndexLinkCtrl.ID = "pageNextIndexLinkCtrl";
                pageNextIndexLinkCtrl.ToolTip = "Next";
                pageNextIndexLinkCtrl.Click += new EventHandler(OnPageShowNext_Click);
                pageNextIndexLinkCtrl.Attributes.Add("class", "next");
                pageNextIndexLinkCtrl.Enabled = (this.CurrentPageIndex < (iTotalPages - 1));
                this.ctrlPageIndexPlaceholder.Controls.Add(pageNextIndexLinkCtrl);

                // Create the "Show All" link...
                LinkButton pageShowAllLinkCtrl = new LinkButton();
                pageShowAllLinkCtrl.ID = "pageShowAllLinkCtrl";
                pageShowAllLinkCtrl.ToolTip = "Show All";
                pageShowAllLinkCtrl.Click += new EventHandler(OnPageShowAll_Click);
                pageShowAllLinkCtrl.Attributes.Add("class", "showAll");
                pageShowAllLinkCtrl.Text = "Show All";
                this.ctrlPageIndexPlaceholder.Controls.Add(pageShowAllLinkCtrl);

                //////////////////////////////////////////////////////////////////
                // Display the count span of items we're displaying:
                int xRecordStart = 1;
                if (this.CurrentPageIndex > 0)
                {
                    xRecordStart = ((this.CurrentPageIndex) * this.PageSize) + 1;
                }

                int yRecordDisplaySpan = pageSize < totalRows ? this.PageSize : totalRows;
                if (this.CurrentPageIndex > 0)
                {
                    yRecordDisplaySpan = (this.CurrentPageIndex + 1) * this.PageSize;

                    if (yRecordDisplaySpan > totalRows)
                    {
                        yRecordDisplaySpan = totalRows;
                    }
                }

                this.ctrlPageDisplayingDetailsLabel.Text = String.Format("displaying {0}-{1} of {2}. sorted by", xRecordStart, yRecordDisplaySpan, totalRows);

                if (sendCurrentPageAdjustmentMsg || forceRefreshAll)
                {
                    // SPECIAL CASE: update so that the parent can sync with other controls...
                    ProWorksPagingControlEventArgs args = this.GetCurrentStateEventArgs();

                    if (forceRefreshAll)
                    {
                        args.EventType = ProWorksPagingControlEventType.Normal;
                    }
                    else
                    {
                        args.EventType = ProWorksPagingControlEventType.CurrentPageOnly;
                    }

                    this.OnPagedControlChanged(this, args);
                }
            }
            catch (Exception x)
            {
                this.ctrlPageDisplayingDetailsLabel.Text = "0 records - error!";
                Label errorLabel = new Label();
                errorLabel.Text = "Internal error loading the paged data.  Details: " + x.Message;

                this.ctrlPageIndexPlaceholder.Controls.Clear();
                this.ctrlPageIndexPlaceholder.Controls.Add(errorLabel);

                umbraco.BusinessLogic.Log.Add(umbraco.BusinessLogic.LogTypes.Error, umbraco.BusinessLogic.User.GetUser(0), -1, errorLabel.Text);
            }
        }

        #endregion

        #region Event Handlers
        protected void OnPageShowPrevious_Click(object sender, System.EventArgs e)
        {
            // Set viewstate variable to the previous page
            int iCurrentPage = this.CurrentPageIndex;
            iCurrentPage--;

            this.CurrentPageIndex = iCurrentPage;

            // Rebind to the current page index...
            if (this.OnPagedControlChanged != null)
            {
                ProWorksPagingControlEventArgs args = this.GetCurrentStateEventArgs();

                this.OnPagedControlChanged(this, args);
            }
        }

        protected void OnPageShowNext_Click(object sender, System.EventArgs e)
        {
            // Set viewstate variable to the next page
            int iCurrentPage = this.CurrentPageIndex;
            iCurrentPage++;

            this.CurrentPageIndex = iCurrentPage;

            // Rebind to the current page index...
            if (this.OnPagedControlChanged != null)
            {
                ProWorksPagingControlEventArgs args = this.GetCurrentStateEventArgs();

                this.OnPagedControlChanged(this, args);
            }
        }

        protected void OnPageShowAll_Click(object sender, System.EventArgs e)
        {
            this.CurrentPageIndex = 0;

            // Set the selection to the last item, which is the text "All"
            this.ctrlPageSizeList.SelectedIndex = this.ctrlPageSizeList.Items.Count - 1;

            // Rebind to the current page index...
            if (this.OnPagedControlChanged != null)
            {
                ProWorksPagingControlEventArgs args = this.GetCurrentStateEventArgs();
                args.EventType = ProWorksPagingControlEventType.PageSizeOnly; 

                // store in local cache...
                this.PageSize = args.PageSize;

                this.OnPagedControlChanged(this, args);
            }
        }

        protected void OnPageSizeListChanged(object sender, EventArgs e)
        {
            if ( suppressMessageFire == true ||
                 this.PageSize == Convert.ToInt32(this.ctrlPageSizeList.SelectedValue))
            {
                return; // no change
            }
            
            // Rebind to the current page index...
            if (this.OnPagedControlChanged != null)
            {
                ProWorksPagingControlEventArgs args = this.GetCurrentStateEventArgs();
                args.EventType = ProWorksPagingControlEventType.PageSizeOnly;

                // store in local cache...
                this.PageSize = args.PageSize;

                this.OnPagedControlChanged(this, args);
            }
        }


        protected void OnSortOrderListChanged(object sender, EventArgs e)
        {
            if (suppressMessageFire == true ||
                this.SortOrderDetails.ToString() == this.ctrlSortOrderList.SelectedValue)
            {
                return; // no change
            }

            if (this.OnPagedControlChanged != null)
            {
                ProWorksPagingControlEventArgs args = this.GetCurrentStateEventArgs();
                args.EventType = ProWorksPagingControlEventType.SortOrderOnly;

                // store in local cache...
                this.SortOrderDetails = args.SortOrderClause.ToString();

                args.EventType = ProWorksPagingControlEventType.SortOrderOnly;

                this.OnPagedControlChanged(this, args);
            }
        }

        protected void OnPageIndexLink_Click(object sender, EventArgs e)
        {
            LinkButton pageIndexBtn = sender as LinkButton;

            // NOTE: the current page is a zero-based index. Displayed indices are 1-based.
            this.CurrentPageIndex = Convert.ToInt32(pageIndexBtn.Text) - 1;

            // Rebind to the current page index...
            if (this.OnPagedControlChanged != null)
            {
                ProWorksPagingControlEventArgs args = this.GetCurrentStateEventArgs();
                this.OnPagedControlChanged(this, args);
            }
        }

        protected void OnExtendedPageDDListSelectChange(object sender, EventArgs e)
        {
            DropDownList extendedPageDDList = sender as DropDownList;

            // NOTE: the current page is a zero-based index. Displayed indices are 1-based.
            this.CurrentPageIndex = Convert.ToInt32(extendedPageDDList.SelectedValue) - 1;

            // Rebind to the current page index...
            if (this.OnPagedControlChanged != null)
            {
                ProWorksPagingControlEventArgs args = this.GetCurrentStateEventArgs();
                this.OnPagedControlChanged(this, args);
            }
        }

        #endregion
   

    }
}